package 进阶阶段;

/**
 * 创建人：刘源江
 * 类描述：
 * 创建时间：2022/8/17 23:36
 **/

public class demo16线程的六种状态和等待唤醒机制 {
    public static void main(String[] args) {
        //线程的六种状态
        //1. NEW(新建)
            //线程刚被创建即new出来的时候，但是并未启动。还没调用start方法。
        //2. Runnable(可运行)
            //线程可以在java虚拟机中运行的状态，可能正在运行自己代码，也可能没有，这取决于操作系统处理器cpu。
        //3. Blocked(锁阻塞)
            //当一个线程试图获取一个对象锁，而该对象锁被其他的线程持有时，该线程进入Blocked状态；当该线程持有
            //锁时，该线程将变成Runnable可运行状态。
        //4. Waiting(无限等待)
            //一个线程在等待另一个线程执行一个（唤醒）动作时，调用wait()方法,该线程进入Waiting状态。进入这个
            //状态后是不能自动唤醒的，必须等待另一个线程调用notify随机唤醒一个或者notifyAll方法才能够唤醒。
        //5. Timed Waiting(计时等待)
            //同waiting状态，有几个方法有超时参数，调用他们将进入Timed Waiting状态。这一状态将一直保持到超时
            //期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep (时间参数)、Object.wait(时间参数5000毫秒自动唤醒)。
        //6. Teminated(被终止)
            //执行完run方法正常退出而死亡，或者因为没有捕获的异常终止了run方法而死亡。

        //多个线程在处理同一个资源，并且任务不同时，需要线程间通信来帮助解决线程之间对同一个变量的使用或操作。
        //或者说多个线程在操作同一份数据时， 避免对同一共享变量的争夺。也就是我们需要通过一定的手段,使各个线程
        //能有效的利用资源。而这种手段即—— 等待唤醒机制。

        //1. wait：线程不再活动，不再参与调度，进入 wait set(等待集合) 中，因此不会浪费 CPU 资源，也不会去竞争
            //锁了，这时的线程状态即是 WAITING。它还要执行一个特别的动作，也即是“通知（notify）”在这个对象上
            //等待的线程从wait set 中释放出来，重新进入到调度队列（ready queue）中
        //2. notify：则选取所通知对象的 wait set 中的一个线程释放；即随机唤醒其中一个等待的线程
        //3. notifyAll：则释放所通知对象的 wait set 上的全部线程。

        //在一个线程进行了规定操作后，就进入等待状态（wait()）， 等待其他线程执行完他们的指定代码过后,再将其唤
        //醒（notify()）;在有多个线程进行等待时， 如果需要，可以使用( notifyAll())来唤醒所有的等待线程。

        BaoZi baoZi = new BaoZi();

        BaoZiPu baoZiPu = new BaoZiPu("包子铺" , baoZi);
        baoZiPu.start();

        ChiHuo chiHuo = new ChiHuo("吃货" , baoZi);
        chiHuo.start();

    }
}

class BaoZi{
    String xian;//包子馅
    boolean flag;//表示包子的状态
}

class BaoZiPu extends Thread{

    BaoZi baoZi;

    public BaoZiPu(String name , BaoZi baoZi) {
        super(name);
        this.baoZi = baoZi;
    }

    @Override
    public void run() {

        int count = 1;

        while (count <= 10){
            synchronized (baoZi){//包子对象baoZi只能有一个，作为锁
                //如果没有包子，包子铺应该生产包子，有包子应该等待
                if (baoZi.flag == true){//有包子时进行等待
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (count%2 == 0){
                    baoZi.xian = "豆腐韭菜馅";
                }else {
                    baoZi.xian = "瘦肉馅";
                }
                baoZi.flag = true;
                System.out.println(getName() + "生产了第" + count + "个包子：" + baoZi.xian);
                count++;

                //吃包子有时间，设置一个睡眠的时间
                try {
                    sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                baoZi.notify();
            }
        }
    }
}

class ChiHuo extends Thread{

    BaoZi baoZi;

    public ChiHuo(String name , BaoZi baoZi) {
        super(name);
        this.baoZi = baoZi;
    }

    @Override
    public void run() {

        while (true){
            synchronized (baoZi){//包子对象baoZi只能有一个，作为锁

                //如果有包子，吃货就吃包子
                if (baoZi.flag == true){
                    System.out.println("吃货吃了" + baoZi.xian + "的包子");
                    baoZi.flag = false;
                    baoZi.notify();
                }else{
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
